﻿using System;
using System.Web.UI;
using System.Globalization;
using System.Web.UI.WebControls;
using System.ComponentModel;
using System.Reflection;
using System.Collections.Generic;
using System.Collections;

[assembly: System.Web.UI.WebResource("Batik.Web.UI.Controls.ScriptDataSource.Script.js", "application/x-javascript")]

namespace Batik.Web.UI.Controls
{
    public class ScriptDataSource : Control, IPostBackEventHandler, IScriptControl, ICallbackEventHandler
	{
        [Bindable(false), Description(""), Category("Behavior"), DefaultValue("true")]
        public string OnSelectCallback { get; set; }
        public string EntityTypeName { get; set; }
        public string ObjectTypeName { get; set; }
        public string SelectMethod { get; set; }
        public string UpdateMethod { get; set; }
        public string DeleteMethod { get; set; }
        public string InsertMethod { get; set; }

		private ScriptManager _scriptManager;

		internal ScriptManager ScriptManager
		{
			get
			{
				if(this._scriptManager == null)
				{
					Page page = this.Page;
					if(page == null)
					{
						throw new InvalidOperationException("Page cannot be null");
					}
					this._scriptManager = ScriptManager.GetCurrent(page);
					if(this._scriptManager == null)
					{
						throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, "required script manager", new object[] { this.ID }));
					}
				}
				return this._scriptManager;
			}
		}
        protected override void OnPreRender(EventArgs e)
        {
            base.OnPreRender(e);
            if (!DesignMode)
            {
                this.ScriptManager.RegisterScriptControl<ScriptDataSource>(this);
                this.ScriptManager.RegisterScriptDescriptors(this);
                this.Page.ClientScript.GetPostBackEventReference(new PostBackOptions(this, string.Empty));
            }
        }

  		#region IPostBackEventHandler Members

		public void RaisePostBackEvent(string eventArgument)
		{
			throw new NotImplementedException();
		}

		#endregion

		#region IScriptControl Members

		System.Collections.Generic.IEnumerable<ScriptDescriptor> IScriptControl.GetScriptDescriptors()
		{
			//ClientScriptManager scriptManager = Page.ClientScript;
			//String callbackReference = scriptManager.GetCallbackEventReference(this, "arg", "Type.createDelegate(this, this._selectCallback)", "window", "function() { alert('error');}", true);
			ScriptComponentDescriptor descriptor = new ScriptComponentDescriptor("Batik.Data.ScriptDataSource");
            descriptor.AddProperty("objectTypeName", ObjectTypeName);
            descriptor.AddProperty("selectMethod", SelectMethod);
            descriptor.AddProperty("deleteMethod", DeleteMethod);
            descriptor.AddProperty("updateMethod", UpdateMethod);
            descriptor.AddProperty("insertMethod", InsertMethod);
            descriptor.AddProperty("id", ID);
            //descriptor.AddScriptProperty("_select", String.Format("function(arg, context) {{{0}; }}", callbackReference));
			yield return descriptor;
		}

		System.Collections.Generic.IEnumerable<ScriptReference> IScriptControl.GetScriptReferences()
		{
			yield return new ScriptReference("Batik.Web.UI.Controls.ScriptDataSource.Script.js", this.GetType().Assembly.FullName);
		}

		#endregion

		string jsonResult;
   
		#region ICallbackEventHandler Members

		string ICallbackEventHandler.GetCallbackResult()
		{
			return jsonResult;
		}

		void ICallbackEventHandler.RaiseCallbackEvent(string eventArgument)
		{
            Type type = this.Page.GetType();
            object instance = type.BaseType.Assembly.CreateInstance(ObjectTypeName);

            System.Web.Script.Serialization.JavaScriptSerializer jsSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
            if (!string.IsNullOrEmpty(eventArgument))
            {
                ScriptDataSourceEventArgs argument =
                    jsSerializer.Deserialize<ScriptDataSourceEventArgs>(eventArgument);
                this.ObjectTypeName = argument.TypeName;
                if (instance != null)
                {
                    object returnValue;
                    MethodInfo methodInfo = instance.GetType().GetMethod(argument.CommandMethod);
                    object[] parameters = argument.Parameters;
                    ArrayList paramArray = new ArrayList();
                    if (parameters != null)
                    {
                        foreach (Dictionary<string, object> dic in parameters)
                        {
                            object paramInstance = type.BaseType.Assembly.CreateInstance(EntityTypeName);
                            Type paramType = paramInstance.GetType();
                            foreach (string key in dic.Keys)
                            {
                                PropertyInfo prop = paramType.GetProperty(key);
                                prop.SetValue(paramInstance, System.Convert.ChangeType(dic[key], prop.PropertyType), null);
                                //paramType.InvokeMember(key, BindingFlags.SetProperty | BindingFlags.Public | BindingFlags.Instance, null, paramInstance, new object[] { dic[key] });
                            }
                            paramArray.Add(paramInstance);
                        }
                        returnValue = methodInfo.Invoke(this.Page, paramArray.ToArray());
                    }
                    else
                    {
                        returnValue = methodInfo.Invoke(this.Page, null);
                    }
                    if (returnValue is int)
                    {
                        jsonResult = returnValue.ToString();
                    }
                    else
                    {
                        jsonResult = jsSerializer.Serialize(returnValue);
                    }
                }
            }
		}
		#endregion
	}
}
